home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / arp.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  11KB  |  393 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "iface.h"
  8. #include "enet.h"
  9. #include "ax25.h"
  10. #include "arp.h"
  11. #ifdef    UNIX
  12. #include <memory.h>
  13. #endif
  14.  
  15. extern int32 ip_addr;        /* Our IP address */
  16.  
  17. /* ARP entries for particular subnetwork types. The table values
  18.  * are filled in by calls to arp_init() at device attach time
  19.  */
  20. #define    NTYPES    9
  21. struct arp_type arp_type[NTYPES];
  22.  
  23. /* Hash table headers */
  24. struct arp_tab *arp_tab[ARPSIZE];
  25.  
  26. struct arp_stat arp_stat;
  27.  
  28. /* Initialize an entry in the ARP table
  29.  * Called by the device driver at attach time
  30.  */
  31. arp_init(hwtype,hwalen,iptype,arptype,bdcst,format,scan)
  32. unsigned int hwtype;    /* ARP Hardware type */
  33. int hwalen;        /* Hardware address length */
  34. int iptype;        /* Subnet's protocol ID for IP */
  35. int arptype;        /* Subnet's protocol ID for ARP */
  36. char *bdcst;        /* Subnet's broadcast address (if any) */
  37. int (*format)();    /* Function to format hardware addresses */
  38. int (*scan)();        /* Function to scan addresses in ascii */    
  39. {
  40.     register struct arp_type *at;
  41.  
  42.     if(hwtype >= NTYPES)
  43.         return -1;    /* Table too small */
  44.  
  45.     at = &arp_type[hwtype];
  46.     at->hwalen = (int16)hwalen;
  47.     at->iptype = (int16)iptype;
  48.     at->arptype = (int16)arptype;
  49.     at->bdcst = bdcst;
  50.     at->format = format;
  51.     at->scan = scan;
  52.     return 0;
  53. }
  54.  
  55. /* Resolve an IP address to a hardware address; if not found,
  56.  * initiate query and return NULLCHAR.  If an address is returned, the
  57.  * interface driver may send the packet; if NULLCHAR is returned,
  58.  * res_arp() will have saved the packet on its pending queue,
  59.  * so no further action (like freeing the packet) is necessary.
  60.  */
  61. char *
  62. res_arp(interface,hardware,target,bp)
  63. struct interface *interface;    /* Pointer to interface block */
  64. int16 hardware;        /* Hardware type */
  65. int32 target;        /* Target IP address */
  66. struct mbuf *bp;    /* IP datagram to be queued if unresolved */
  67. {
  68.     void arp_output();
  69.     register struct arp_tab *arp;
  70.  
  71.     if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  72.         return arp->hw_addr;
  73.     /* Create an entry and put the datagram on the
  74.      * queue pending an answer
  75.      */
  76.     arp = arp_add(target,hardware,NULLCHAR,0,0);
  77.     enqueue(&arp->pending,bp);
  78.     arp_output(interface,hardware,target);
  79.     return NULLCHAR;
  80. }
  81. /* Handle incoming ARP packets. This is almost a direct implementation of
  82.  * the algorithm on page 5 of RFC 826, except for:
  83.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  84.  *    pending a reply to our ARP request.
  85.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  86.  * 3. Requests for IP addresses listed in our table as "published" are
  87.  *    responded to, even if the address is not our own.
  88.  */
  89. void
  90. arp_input(interface,bp)
  91. struct interface *interface;
  92. struct mbuf *bp;
  93. {
  94.     struct arp arp;
  95.     struct arp_tab *ap;
  96.     struct arp_type *at;
  97.     struct mbuf *htonarp();
  98.     
  99.     arp_stat.recv++;
  100.     if(ntoharp(&arp,&bp) == -1)    /* Convert into host format */
  101.         return;
  102.     if(arp.hardware >= NTYPES){
  103.         /* Unknown hardware type, ignore */
  104.         arp_stat.badtype++;
  105.         return;
  106.     }
  107.     at = &arp_type[arp.hardware];
  108.     if(arp.protocol != at->iptype){
  109.         /* Unsupported protocol type, ignore */
  110.         arp_stat.badtype++;
  111.         return;
  112.     }
  113.     if(uchar(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  114.         /* Incorrect protocol addr length (different hw addr lengths
  115.          * are OK since AX.25 addresses can be of variable length)
  116.          */
  117.         arp_stat.badlen++;
  118.         return;
  119.     }
  120.     if(memcmp(arp.shwaddr,at->bdcst,(int)at->hwalen) == 0){
  121.         /* This guy is trying to say he's got the broadcast address! */
  122.         arp_stat.badaddr++;
  123.         return;
  124.     }
  125.     /* If this guy is already in the table, update its entry
  126.      * unless it's a manual entry (noted by the lack of a timer)
  127.      */
  128.     ap = NULLARP;    /* ap plays the role of merge_flag in the spec */
  129.     if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  130.      && ap->timer.start != 0){
  131.         ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  132.     }
  133.     /* See if we're the address they're looking for */
  134.     if(arp.tprotaddr == ip_addr){
  135.         if(ap == NULLARP)    /* Only if not already in the table */
  136.             arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  137.  
  138.         if(arp.opcode == ARP_REQUEST){
  139.             /* Swap sender's and target's (us) hardware and protocol
  140.              * fields, and send the packet back as a reply
  141.              */
  142.             memcpy(arp.thwaddr,arp.shwaddr,(int)uchar(arp.hwalen));
  143.             /* Mark the end of the sender's AX.25 address
  144.              * in case he didn't
  145.              */
  146.             if(arp.hardware == ARP_AX25)
  147.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  148.  
  149.             memcpy(arp.shwaddr,interface->hwaddr,(int)at->hwalen);
  150.             arp.tprotaddr = arp.sprotaddr;
  151.             arp.sprotaddr = ip_addr;
  152.             arp.opcode = ARP_REPLY;
  153.             if((bp = htonarp(&arp)) == NULLBUF)
  154.                 return;
  155.  
  156.             if(interface->forw != NULLIF)
  157.                 (*interface->forw->output)(interface->forw,
  158.                  arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  159.             else 
  160.                 (*interface->output)(interface,arp.thwaddr,
  161.                  interface->hwaddr,at->arptype,bp);
  162.             arp_stat.inreq++;
  163.         } else {
  164.             arp_stat.replies++;
  165.         }
  166.     } else if(arp.opcode == ARP_REQUEST
  167.         && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  168.         && ap->pub){
  169.         /* Otherwise, respond if the guy he's looking for is
  170.          * published in our table.
  171.          */
  172.         memcpy(arp.thwaddr,arp.shwaddr,(int)uchar(arp.hwalen));
  173.         /* Mark the end of the sender's AX.25 address
  174.          * in case he didn't
  175.          */
  176.         if(arp.hardware == ARP_AX25)
  177.             arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  178.         memcpy(arp.shwaddr,ap->hw_addr,(int)at->hwalen);
  179.         arp.tprotaddr = arp.sprotaddr;
  180.         arp.sprotaddr = ap->ip_addr;
  181.         arp.opcode = ARP_REPLY;
  182.         if((bp = htonarp(&arp)) == NULLBUF)
  183.             return;
  184.         if(interface->forw != NULLIF)
  185.             (*interface->forw->output)(interface->forw,
  186.              arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  187.         else 
  188.             (*interface->output)(interface,arp.thwaddr,
  189.              interface->hwaddr,at->arptype,bp);
  190.         arp_stat.inreq++;
  191.     }
  192. }
  193. /* Add an IP-addr / hardware-addr pair to the ARP table */
  194. struct arp_tab *
  195. arp_add(ipaddr,hardware,hw_addr,hw_alen,pub)
  196. int32 ipaddr;        /* IP address, host order */
  197. int16 hardware;        /* Hardware type */
  198. char *hw_addr;        /* Hardware address, if known; NULLCHAR otherwise */
  199. int16 hw_alen;        /* Length of hardware address */
  200. int pub;        /* Publish this entry? */
  201. {
  202.     void arp_drop();
  203.     int ip_route();
  204.     struct mbuf *bp,*dequeue();
  205.     register struct arp_tab *ap;
  206.     unsigned hashval,arp_hash();
  207.  
  208.     if((ap = arp_lookup(hardware,ipaddr)) == NULLARP){
  209.         /* New entry */
  210.         if((ap = (struct arp_tab *)calloc(1,sizeof(struct arp_tab))) == NULLARP)
  211.             return NULLARP;
  212.         ap->timer.func = arp_drop;
  213.         ap->timer.arg = (char *)ap;
  214.         ap->hardware = hardware;
  215.         ap->ip_addr = ipaddr;
  216.  
  217.         /* Put on head of hash chain */
  218.         hashval = arp_hash(hardware,ipaddr);
  219.         ap->prev = NULLARP;
  220.         ap->next = arp_tab[hashval];
  221.         arp_tab[hashval] = ap;
  222.         if(ap->next != NULLARP){
  223.             ap->next->prev = ap;
  224.         }
  225.     }
  226.     if(hw_addr == NULLCHAR){
  227.         /* Await response */
  228.         ap->state = ARP_PENDING;
  229.         ap->timer.start = PENDTIME * (1000 / MSPTICK);
  230.     } else {
  231.         /* Response has come in, update entry and run through queue */
  232.         ap->state = ARP_VALID;
  233.         ap->timer.start = ARPLIFE * (1000 / MSPTICK);
  234.         if(ap->hw_addr != NULLCHAR)
  235.             free(ap->hw_addr);
  236.         if((ap->hw_addr = malloc(hw_alen)) == NULLCHAR){
  237.             free((char *)ap);
  238.             return NULLARP;
  239.         }
  240.         memcpy(ap->hw_addr,hw_addr,(int)hw_alen);
  241.         /* This kludge marks the end of an AX.25 address to allow
  242.          * for optional digipeaters (insert Joan Rivers salute here)
  243.          */
  244.         if(hardware == ARP_AX25)
  245.             ap->hw_addr[hw_alen-1] |= E;
  246.         ap->pub = pub;
  247.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  248.             ip_route(bp,0);
  249.     }
  250.     start_timer(&ap->timer);
  251.     return ap;
  252. }
  253.  
  254. /* Remove an entry from the ARP table */
  255. void
  256. arp_drop(ap)
  257. register struct arp_tab *ap;
  258. {
  259.     unsigned arp_hash();
  260.  
  261.     if(ap == NULLARP)
  262.         return;
  263.     stop_timer(&ap->timer);    /* Shouldn't be necessary */
  264.     if(ap->next != NULLARP)
  265.         ap->next->prev = ap->prev;
  266.     if(ap->prev != NULLARP)
  267.         ap->prev->next = ap->next;
  268.     else
  269.         arp_tab[arp_hash(ap->hardware,ap->ip_addr)] = ap->next;
  270.     if(ap->hw_addr != NULLCHAR)
  271.         free(ap->hw_addr);
  272.     free_q(&ap->pending);
  273.     free((char *)ap);
  274. }
  275.  
  276. /* Look up the given IP address in the ARP table */
  277. struct arp_tab *
  278. arp_lookup(hardware,ipaddr)
  279. int16 hardware;
  280. int32 ipaddr;
  281. {
  282.     unsigned arp_hash();
  283.     register struct arp_tab *ap;
  284.  
  285.     for(ap = arp_tab[arp_hash(hardware,ipaddr)]; ap != NULLARP; ap = ap->next){
  286.         if(ap->ip_addr == ipaddr && ap->hardware == hardware)
  287.             break;
  288.     }
  289.     return ap;
  290. }
  291. /* Send an ARP request to resolve IP address target_ip */
  292. static
  293. void
  294. arp_output(interface,hardware,target)
  295. struct interface *interface;
  296. int16 hardware;
  297. int32 target;
  298. {
  299.     struct arp arp;
  300.     struct mbuf *bp,*htonarp();
  301.     struct arp_type *at;
  302.  
  303.     at = &arp_type[hardware];
  304.     if(interface->output == NULLFP)
  305.         return;
  306.     
  307.     arp.hardware = hardware;
  308.     arp.protocol = at->iptype;
  309.     arp.hwalen = at->hwalen;
  310.     arp.pralen = sizeof(int32);
  311.     arp.opcode = ARP_REQUEST;
  312.     memcpy(arp.shwaddr,interface->hwaddr,(int)at->hwalen);
  313.     arp.sprotaddr = ip_addr;
  314.     memset(arp.thwaddr,0,(int)at->hwalen);
  315.     arp.tprotaddr = target;
  316.     if((bp = htonarp(&arp)) == NULLBUF)
  317.         return;
  318.     (*interface->output)(interface,at->bdcst,
  319.         interface->hwaddr,at->arptype,bp);
  320.     arp_stat.outreq++;
  321. }
  322.  
  323. /* Hash a {hardware type, IP address} pair */
  324. static
  325. unsigned
  326. arp_hash(hardware,ipaddr)
  327. int16 hardware;
  328. int32 ipaddr;
  329. {
  330.     register unsigned hashval;
  331.  
  332.     hashval = hardware;
  333.     hashval ^= hiword(ipaddr);
  334.     hashval ^= loword(ipaddr);
  335.     hashval %= ARPSIZE;
  336.     return hashval;
  337. }        
  338. /* Copy a host format arp structure into mbuf for transmission */
  339. struct mbuf *
  340. htonarp(arp)
  341. register struct arp *arp;
  342. {
  343.     struct mbuf *bp;
  344.     register char *buf;
  345.  
  346.     if(arp == (struct arp *)NULL)
  347.         return NULLBUF;
  348.     if((bp = alloc_mbuf(sizeof(struct arp))) == NULLBUF)
  349.         return NULLBUF;
  350.  
  351.     buf = bp->data;
  352.  
  353.     buf = put16(buf,arp->hardware);
  354.     buf = put16(buf,arp->protocol);
  355.     *buf++ = arp->hwalen;
  356.     *buf++ = arp->pralen;
  357.     buf = put16(buf,arp->opcode);
  358.     memcpy(buf,arp->shwaddr,(int)uchar(arp->hwalen));
  359.     buf += arp->hwalen;
  360.     buf = put32(buf,arp->sprotaddr);
  361.     memcpy(buf,arp->thwaddr,(int)uchar(arp->hwalen));
  362.     buf += arp->hwalen;
  363.     buf = put32(buf,arp->tprotaddr);
  364.  
  365.     bp->cnt = buf - bp->data;
  366.     return bp;
  367. }
  368. /* Convert an incoming ARP packet into a host-format structure */
  369. int
  370. ntoharp(arp,bpp)
  371. register struct arp *arp;
  372. struct mbuf **bpp;
  373. {
  374.     if(arp == (struct arp *)NULL || bpp == NULLBUFP)
  375.         return -1;
  376.  
  377.     arp->hardware = pull16(bpp);
  378.     arp->protocol = pull16(bpp);
  379.     arp->hwalen = pullchar(bpp);
  380.     arp->pralen = pullchar(bpp);
  381.     arp->opcode = pull16(bpp);
  382.     pullup(bpp,arp->shwaddr,(int16)uchar(arp->hwalen));
  383.     arp->sprotaddr = pull32(bpp);
  384.     pullup(bpp,arp->thwaddr,(int16)uchar(arp->hwalen));
  385.  
  386.     arp->tprotaddr = pull32(bpp);
  387.  
  388.     /* Get rid of anything left over */
  389.     free_p(*bpp);
  390.     *bpp = NULLBUF;
  391.     return 0;
  392. }
  393.